



import sys
import traceback
from redis import Redis
import json
from sqlalchemy.orm import Session
from app import ctx_conf
from app import services
from app.common.enums import ErrTypes
from app.common.exceptions import GenericException

import logging
logger = logging.getLogger(__name__)

from .v1.rule_parser import RuleParser as v1

default_version = v1

RISK_RULE_KEY = 'risk_rule'


def get_rule_parser(version: str):
    if version == '1.0':
        return v1
    else:
        return default_version


def parse_trans_rules(params: dict):
    logger.info('>> parse_trans_rules')
    app = ctx_conf.get('app')
    r: Redis = app.r
    rules = read_all_rules(r)
    rules = sorted(rules, key=lambda x: x['priority'])
    logger.info('规则总数: %s' % len(rules))
    result = True
    for rule in rules:
        tpl = json.loads(rule.get('rule_tpl'))
        rule_name = rule.get("rule_name")
        fail_msg = rule.get('fail_msg') or f'风控规则[{rule_name}]校验不通过'
        version = tpl.get('version')
        Parser = get_rule_parser(version)
        parser = Parser(r, tpl, params)
        result = parser.parse()
        if not result:
            logger.info(fail_msg)
            raise GenericException(ErrTypes.risk_rule_not_pass, message=fail_msg)
    return result


def read_all_rules(r: Redis):
    logger.info('>> read_all_rules')
    keys = r.keys(f'{RISK_RULE_KEY}:*')
    rules = []
    if not keys:
        logger.warning('风控缓存规则为空, 刷新缓存')
        from app.common.database import get_db
        db: Session = next(get_db())
        services.risk.refresh_risk_rule_cache(db, r)
        keys = r.keys(f'{RISK_RULE_KEY}:*')
    for k in keys:
        rjs = r.get(k)
        try:
            dt = json.loads(rjs)
            rules.append(dt)
        except Exception as err:
            logger.error('获取规则模板缓存数据出错, Key: %s' % k)
            exc_type, exc_value, exc_obj = sys.exc_info()
            traceback.print_exception(exc_type,exc_value,exc_obj,limit=3,file=sys.stdout)
            raise GenericException(ErrTypes.trans_create_fail)
    logger.info(f'读取缓存规则模板数据完成，总计 {len(rules)} 条数据')
    return rules
